/*
DOES NOT USE BUILT-IN DETECTION FUNCTIONALITY!!

alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (msg:"WEB-CLIENT Microsoft Color Management System EMF file processing overflow attempt"; flow:to_client,established; content:"|01 00 00 00|"; content:"|20|EMF"; distance:36; within:4; content:"|79 00 00 00|"; distance:0; metadata:policy balanced-ips drop, policy security-ips drop, service http; reference:cve,2008-2245; reference:url,,technet.microsoft.com/en-us/security/bulletin/ms08-046; classtype:attempted-user; sid:13954; rev:1;)
*/

/*
 * Use at your own risk.
 *
 * Copyright (C) 2005-2008 Sourcefire, Inc.
 * 
 * This file is autogenerated via rules2c, by Brian Caswell <bmc@sourcefire.com>
 */

#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

#include "so-util.h"

//#define DEBUG
#ifdef DEBUG
#define DEBUG_WRAP(code) code
#else
#define DEBUG_WRAP(code)
#endif

/* declare detection functions */
int rule13954eval(void *p);

/* declare rule data structures */
/* precompile the stuff that needs pre-compiled */
/* flow:established, to_client; */
static FlowFlags rule13954flow0 = 
{
    FLOW_ESTABLISHED|FLOW_TO_CLIENT
};

static RuleOption rule13954option0 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule13954flow0
    }
};
// content:"|01 00 00 00|"; 
static ContentInfo rule13954content1 = 
{
    (uint8_t *) "|01 00 00 00|", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_BUF_NORMALIZED, /* flags */ 
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule13954option1 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule13954content1
    }
};
// content:" EMF", offset 36, depth 4, relative; 
static ContentInfo rule13954content2 = 
{
    (uint8_t *) " EMF", /* pattern (now in snort content format) */
    4, /* depth */
    36, /* offset */
    CONTENT_FAST_PATTERN|CONTENT_RELATIVE|CONTENT_BUF_NORMALIZED, /* flags */ 
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule13954option2 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule13954content2
    }
};
// content:"y|00 00 00 00|", relative; 
static ContentInfo rule13954content3 = 
{
    (uint8_t *) "y|00 00 00|", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_RELATIVE|CONTENT_BUF_NORMALIZED, /* flags */ 
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule13954option3 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule13954content3
    }
};

/* references for sid 13954 */
/* reference: cve "2008-2245"; */
static RuleReference rule13954ref1 = 
{
    "cve", /* type */
    "2008-2245" /* value */
};

/* reference: url ",technet.microsoft.com/en-us/security/bulletin/ms08-046"; */
static RuleReference rule13954ref2 = 
{
    "url", /* type */
    "technet.microsoft.com/en-us/security/bulletin/ms08-046" /* value */
};

static RuleReference *rule13954refs[] =
{
    &rule13954ref1,
    &rule13954ref2,
    NULL
};
/* metadata for sid 13954 */
/* metadata:service http, policy balanced-ips drop, policy security-ips drop; */
static RuleMetaData rule13954service1 = 
{
    "service http"
};


static RuleMetaData rule13954policy1 = 
{
    "policy max-detect-ips drop"
};
//
//static RuleMetaData rule13954policy2 = 
//{
//    "policy security-ips drop"
//};


static RuleMetaData *rule13954metadata[] =
{
    &rule13954service1,
    &rule13954policy1,
//    &rule13954policy2,
    NULL
};
RuleOption *rule13954options[] =
{
    &rule13954option0,
    &rule13954option1,
    &rule13954option2,
    &rule13954option3,
    NULL
};

Rule rule13954 = {
   
   /* rule header, akin to => tcp any any -> any any               */{
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "$HTTP_PORTS", /* SRCPORT   */
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
       "any", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid (HARDCODED!!!) */
       13954, /* sigid */
       10, /* revision */
   
       "attempted-user", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "OS-WINDOWS Microsoft Color Management System EMF file processing overflow attempt",     /* message */
       rule13954refs /* ptr to references */
       ,rule13954metadata
   },
   rule13954options, /* ptr to rule options */
   &rule13954eval, /* DO NOT use the built in detection function */
   0 /* am I initialized yet? */
};


/* detection functions */
int rule13954eval(void *p) {
    const uint8_t *cursor_normal = 0, *beg_of_payload, *end_of_payload, *end_of_record;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    uint32_t dParmSize;

    DEBUG_WRAP(printf("rule13954eval (MS CMS EMF) enter\n"));

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
   
    // flow:established, to_client;
    if (checkFlow(p, rule13954options[0]->option_u.flowFlags) > 0 ) {
        // content:"|01 00 00 00|";
        if (contentMatch(p, rule13954options[1]->option_u.content, &cursor_normal) > 0) {
            // content:" EMF", offset 36, depth 4, relative;
            if (contentMatch(p, rule13954options[2]->option_u.content, &cursor_normal) > 0) {

                if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                     return RULE_NOMATCH;

                // content:"y|00 00 00 00|", relative;
                // This record can happen multiple times.  It's already relative:0 so loop!
                while (contentMatch(p, rule13954options[3]->option_u.content, &cursor_normal) > 0) {
                    DEBUG_WRAP(printf("Found record\n"));
                    if(cursor_normal + 6 >= end_of_payload) 
                       return RULE_NOMATCH;

                    dParmSize = read_little_32(cursor_normal);
                    DEBUG_WRAP(printf("dParmSize = %d\n", dParmSize));
                  
                    end_of_record = cursor_normal + 4 + dParmSize; // Type/Size/dParm
                    if(end_of_record > end_of_payload || end_of_record < cursor_normal + 4) {
                       end_of_record = end_of_payload; 
                    }
               
                    cursor_normal += 20;  // skip over record header info
                    while(cursor_normal < end_of_record) {
                       // "|00 00 00|" is end of the data we care about
                       // "|3a 00|" not followed by "|5c 00|" is exploit attempt
                       switch(*cursor_normal) {
                          case ':': 
                             DEBUG_WRAP(printf("Found 0x3a\n"));
                             if(cursor_normal + 1 < end_of_record) {
                                if(*(cursor_normal + 1) == 0x00) {
                                   // due to an exploit in the wild where the file terminates
                                   // at this point, we're going to leave in a slight possibility
                                   // of a false positive if we happen to be at a packet break
                                   if((cursor_normal + 3) >= end_of_record ||
                                         (*(cursor_normal + 2) != '\\') || (*(cursor_normal + 3) != 0x00))
                                      return RULE_MATCH;
                                }
                             }
                             break;
                          case 0x00:
                             if(cursor_normal + 2 < end_of_record) {
                                if(*(cursor_normal + 1) == 0x00 && *(cursor_normal + 2) == 0x00) {
                                   // Found terminator.  Look for next matching record.
                                   cursor_normal = end_of_record; 
                                   continue; // continue instead of break to avoid increment below
                                }
                             } 
                             break;
                       }

                       cursor_normal++;
                    } 
                }
            }
        }
    }
    return RULE_NOMATCH;
}

/*
Rule *rules[] = {
    &rule13954,
    NULL
};
*/

